/**
  ******************************************************************************
  * @file    OLED_SSD1315_Config.c
  * @brief   I2C总线模拟驱动OLED（软件实现）
  * @author  18408107475@163.com
  * @version V1.0.0
  * @date    2025-6-15
  * @note    硬件特性：
  *          - 显示面板：128x64 有机LED（单色，黑底白字）
  *          - 控制器：Solomon Systech SSD1315（兼容SSD1306）
  *          - 接口：I2C（支持标准模式100kHz和高速模式400kHz）
  *          - 显存组织：8页（Page0~Page7）×128列×8位（每页含8行像素）
  *          - 电源需求：3.3V供电，内置DC-DC电荷泵（将3.3V升压至7-8V驱动OLED）
  *
  * @attention 移植说明：
  *          1. 硬件连接：
  *             - SCL：PB6（需外接4.7KΩ上拉电阻至3.3V，I2C总线必需）
  *             - SDA：PB7（同上拉电阻）
  *             - RESET：建议接硬件复位电路（10uF电容+10KΩ电阻下拉至GND，上电自动复位）
  *          2. 软件适配：
  *             - 修改IIC_GPIO_Config()中的GPIO端口定义（若更换引脚）
  *             - 确保Delay_us()函数精度（至少±10%，影响I2C时序）
  *             - 字库（OLED_SSD1315_Font.h）需存储在Flash（程序存储器），节省RAM
  *          3. 功耗说明：
  *             - 全亮模式：约20mA（取决于亮度）
  *             - 休眠模式（Display Off）：<10uA（仅保留寄存器供电）
  ******************************************************************************
  */

/* 包含头文件 ----------------------------------------------------------------*/
#include "OLED_SSD1315_Config.h"  // OLED配置头文件（宏定义、函数声明）
#include "OLED_SSD1315_Font.h"    // 字库文件（包含6x8/8x16 ASCII、16x16汉字点阵）

/*
	OLED的显存映射（硬件规定的存储结构）
	格式说明：
	- 共8页（Page0~Page7），对应屏幕64行（每页8行）
	- 每页128列（Column0~Column127），对应屏幕水平像素
	- 每个存储单元为8位（bit0~bit7），控制对应列的8行像素（bit0为最顶行）
	示例：Page0的Column0存储0x01 → 该列第0行像素点亮，其余7行熄灭
*/

/**
  * @brief  I2C起始信号（底层时序）
  * @note   产生I2C总线起始条件：
  *         1. SCL线为高电平时，SDA线从高电平跳变为低电平
  *         2. 时序要求：SDA低电平建立时间≥4.7us，SCL高电平保持时间≥4.0us
  *         3. 调用IIC_Start()（软件模拟I2C时序的底层函数）
  */
void OLED_SSD1315_Start(void)
{
    IIC_Start();  // 调用软件I2C驱动的起始信号函数
}

/**
  * @brief  I2C停止信号（底层时序）
  * @note   产生I2C总线停止条件：
  *         1. SCL线为高电平时，SDA线从低电平跳变为高电平
  *         2. 时序要求：SDA高电平建立时间≥4.7us，SCL高电平保持时间≥4.0us
  *         3. 调用IIC_Stop()（软件模拟I2C时序的底层函数）
  */
void OLED_SSD1315_Stop(void)
{
    IIC_Stop();   // 调用软件I2C驱动的停止信号函数
}

/**
  * @brief  等待从机应答（检测I2C通信状态）
  * @retval true: 收到ACK（从机应答）, false: 无应答（通信失败）
  * @note   应答检测逻辑：
  *         1. 主机释放SDA线（置为输入），发送1个SCL高电平
  *         2. 若SDA线为低电平 → 从机应答（ACK）
  *         3. 若SDA线为高电平 → 从机无应答（NACK）
  *         4. 时序要求：SCL高电平保持时间≥4.0us
  */
bool OLED_SSD1315_Wait_ACK(void)
{
    return IIC_Wait_Ack();  // 调用软件I2C驱动的应答检测函数
}

/**
  * @brief  向OLED写入命令（配置控制器参数）
  * @param  IIC_command: 要写入的命令字节（SSD1315寄存器地址或配置值）
  * @retval true: 写入成功, false: 写入失败（无应答）
  * @note   OLED命令传输格式（I2C协议）：
  *         1. 发送从机地址（OLED_SSD1315_SLAVE_ADDRESS，7位地址+写标志0 → 0x78）
  *         2. 发送控制字节（0x00 → 表示后续数据为命令）
  *         3. 发送命令字节（IIC_command）
  *         4. 等待从机应答，返回通信结果
  */
bool OLED_SSD1315_Write_Command(u8 IIC_command)
{
    // 调用底层I2C写函数：地址+命令标识（0x00）+命令字节
    return IIC_Write_Data(OLED_SSD1315_SLAVE_ADDRESS, WRITE_COMMAND, IIC_command);
}

/**
  * @brief  向OLED写入数据（更新显示内容）
  * @param  IIC_Data: 要写入的显存数据字节（控制像素点亮/熄灭）
  * @retval true: 写入成功, false: 写入失败（无应答）
  * @note   OLED数据传输格式（I2C协议）：
  *         1. 发送从机地址（OLED_SSD1315_SLAVE_ADDRESS，0x78）
  *         2. 发送控制字节（0x40 → 表示后续数据为显存数据）
  *         3. 发送数据字节（IIC_Data，每字节控制8个像素）
  *         4. 等待从机应答，返回通信结果
  */
bool OLED_SSD1315_Write_Data(u8 IIC_Data)
{
	// 调用底层I2C写函数：地址+数据标识（0x40）+数据字节
	return IIC_Write_Data(OLED_SSD1315_SLAVE_ADDRESS, WRITE_DATA, IIC_Data);
}

/**
  * @brief  通用数据/命令写入函数（简化调用）
  * @param  Input_Value: 要写入的值（命令或数据）
  * @param  Mode_selet: 模式选择（OLED_CMD=命令, OLED_DATA=数据）
  * @note   功能：根据Mode_selet自动调用Write_Command或Write_Data
  *         优势：减少重复代码，提高可读性
  */
void OLED_SSD1315_Dat_or_Cmd(u8 Input_Value, u8 Mode_selet)
{
	// 三元运算符：Mode_selet为真则写数据，否则写命令
	(Mode_selet) ? OLED_SSD1315_Write_Data(Input_Value) : OLED_SSD1315_Write_Command(Input_Value);
}

/**
 * @brief 填充整个OLED屏幕（128x64）为指定模式
 * @param pattern 填充模式（0x00=全灭，0xFF=全亮，0x55=交替亮灭等自定义图案）
 * @return true: 填充成功, false: 失败（I2C通信错误）
 * @note   填充原理：
 *         1. 遍历OLED的8页（Page0~Page7）
 *         2. 对每页设置起始列地址（0x00~0x7F）
 *         3. 向该页的128列写入pattern值
 *         性能：
 *         - 总传输数据量=8页×128列=1024字节
 *         - I2C@400kHz时，单字节传输约25us → 总耗时≈25us×1024≈25.6ms
 */
bool OLED_SSD1315_FillScreen(u8 pattern) 
{
    u8 page, col;  // page：页索引（0~7），col：列索引（0~127）
    
    for (page = 0; page < 8; page++)  // 遍历8页
    {
        /* 设置当前页地址：命令0xB0 | page（0xB0为页地址基值） */
        if (!OLED_SSD1315_Write_Command(0xB0 | page)) {
            return false;  // 页地址设置失败，返回错误
        }
        
        /* 设置列地址：分高低4位（SSD1315地址为8位，需分两次传输）
           - 低4位：0x00（基值） | (col低4位)，此处col=0 → 0x00
           - 高4位：0x10（基值） | (col高4位)，此处col=0 → 0x10 */
        if (!OLED_SSD1315_Write_Command(0x00) || 
            !OLED_SSD1315_Write_Command(0x10)) {
            return false;  // 列地址设置失败，返回错误
        }
        
        /* 填充当前页的128列 */
        for (col = 0; col < 128; col++) 
        {
            if (!OLED_SSD1315_Write_Data(pattern)) {
                return false;  // 数据写入失败，返回错误
            }
        }
    }
    return true;  // 所有页填充完成，返回成功
}

/**
  * @brief  设置显示起始位置（定位到指定像素坐标）
  * @param  x: 水平坐标（列地址，0~127）→ 对应屏幕X轴
  * @param  y: 垂直坐标（页地址，0~7）→ 对应屏幕Y轴（每页含8行，实际像素行= y×8 + 行内偏移）
  * @note   SSD1315寻址机制（分页式寻址模式）：
  *         1. 页地址：由命令0xB0~0xB7指定（0xB0+page）
  *         2. 列地址：8位地址分两次传输：
  *            - 低4位：0x00~0x0F（命令0x00 | 低4位）
  *            - 高4位：0x10~0x1F（命令0x10 | 高4位）
  *         3. 地址自动递增：写入数据后，列地址自动+1，页地址不变；
  *            列地址满128后，自动回到0，但页地址不变（需手动切换页）
  */
void OLED_SSD1315_Set_Pos(u8 x, u8 y)
{ 	
	/* 设置页地址（Y轴）：0xB0 | (y & 0x07) → 确保y在0~7范围内 */
    OLED_SSD1315_Dat_or_Cmd(0xB0 | (y & 0x07), OLED_CMD);
	/* 设置列地址高4位：((x & 0xF0) >> 4) | 0x10 → 提取x的高4位 */
    OLED_SSD1315_Dat_or_Cmd(((x & 0xF0) >> 4) | 0x10, OLED_CMD);
	/* 设置列地址低4位：x & 0x0F → 提取x的低4位 */
    OLED_SSD1315_Dat_or_Cmd((x & 0x0F), OLED_CMD);
}

/**
  * @brief  开启显示并配置电荷泵（核心电源管理）
  * @note   电源启动流程：
  *         1. 命令0x8D：进入电荷泵配置模式
  *         2. 命令0x14：启用内部电荷泵（DC-DC转换器，将3.3V升压至7-8V，驱动OLED阳极）
  *         3. 命令0xAF：退出休眠模式，开启显示输出
  *         硬件细节：
  *         - 电荷泵需外接10uF以上滤波电容（靠近OLED电源引脚）
  *         - 升压启动时间约500us，故延迟1ms确保电压稳定
  *         - 禁用电荷泵（0x10）时，需外部提供7-8V电源，否则无法点亮
  */
void OLED_SSD1315_Display_On(void)
{
    OLED_SSD1315_Dat_or_Cmd(0x8D, OLED_CMD);  // 电荷泵配置命令
    OLED_SSD1315_Dat_or_Cmd(0x14, OLED_CMD);  // 启用电荷泵（0x10为禁用）
	Delay_ms(1);                      		  // 等待电荷泵稳定
    OLED_SSD1315_Dat_or_Cmd(0xAF, OLED_CMD);  // 开启显示（0xAE为关闭）
}

/**
  * @brief  关闭显示并进入低功耗模式
  * @note   低功耗流程：
  *         1. 命令0xAE：关闭显示输出（停止扫描，显存数据保留）
  *         2. 命令0x8D：进入电荷泵配置
  *         3. 命令0x10：关闭电荷泵（节省功耗，仅3.3V待机）
  *         功耗对比：
  *         - 显示关闭但电荷泵开启：≈0.1mA（显存仍供电）
  *         - 显示关闭且电荷泵关闭：<10uA（深度休眠）
  *         唤醒方式：调用OLED_SSD1315_Display_On()重新启用电荷泵并开启显示
  */
void OLED_SSD1315_Display_Off(void)
{
	OLED_SSD1315_Dat_or_Cmd(0xAE, OLED_CMD);  // 关闭显示输出
    OLED_SSD1315_Dat_or_Cmd(0x8D, OLED_CMD);  // 电荷泵配置命令
    OLED_SSD1315_Dat_or_Cmd(0x10, OLED_CMD);  // 关闭电荷泵
}

/**
  * @brief  清屏函数（快速清除所有显示内容）
  * @note   实现原理：调用FillScreen填充0x00（所有像素熄灭）
  *         优势：比逐像素清除快100倍以上（直接操作显存块）
  *         注意：清屏后显存数据全为0，但寄存器配置不变（无需重新初始化）
  */
void OLED_SSD1315_Clear(void)
{
	OLED_SSD1315_FillScreen(0x00);	// 全屏写入0x00（全灭）
}

/**
  * @brief  全屏点亮（屏幕测试用）
  * @note   实现原理：调用FillScreen填充0xFF（所有像素点亮）
  *         用途：
  *         - 检测屏幕坏点（无显示的像素为坏点）
  *         - 测试屏幕亮度均匀性
  *         注意：
  *         - 全亮时电流较大（20-30mA），避免长时间点亮影响OLED寿命
  *         - 测试完成后建议清屏（调用OLED_SSD1315_Clear()）
  */
void OLED_SSD1315_ON(void)
{
	OLED_SSD1315_FillScreen(0xFF);	// 全屏写入0xFF（全亮）
}

/**
 * @brief 在指定位置显示一个字符（ASCII码）
 * @param x 列起始位置 (0~127)
 * @param y 行起始位置 (单位: 页, 0~7)
 * @param chr 要显示的字符 (ASCII码，如'A'、'1'、'$'等)
 * @param char_size 字体大小 (8=8x8像素, 16=16x16像素)
 * @note 字库依赖：
 *       - 8x8字体：存储在F6x8数组（实际宽度6像素，节省空间）
 *       - 16x16字体：存储在F8X16数组（宽度8像素）
 *       显示逻辑：
 *       1. 计算字符在字库中的偏移量（chr - ' '，空格为ASCII起始字符）
 *       2. 定位到(x,y)位置
 *       3. 逐列写入字库点阵数据（1字节控制8行像素）
 */
void OLED_SSD1315_ShowChar(u8 x, u8 y, u8 chr, u8 char_size) 
{
    // 参数校验（超出屏幕范围则调整）
    if (x >= OLED_WIDTH) x = 0;  // 列溢出则回滚到0
    if (y >= OLED_PAGE_NUM) y = 0;  // 页溢出则回滚到0
    if (char_size != 8 && char_size != 16) char_size = 8;  // 仅支持8/16两种字体

    // 计算字库偏移量（ASCII码从空格' '开始，偏移量=chr - ' '）
    u8 char_offset = chr - ' ';
    
    // 16x16字体处理（占2页，8列）
    if (char_size == 16) {
        // 显示上半部分（第0页，8行像素）
        OLED_SSD1315_Set_Pos(x, y);
        for (u8 i = 0; i < 8; i++) {  // 写入8列数据
            OLED_SSD1315_Write_Data(F8X16[char_offset * 16 + i]);
        }
        
        // 显示下半部分（第1页，下8行像素）
        OLED_SSD1315_Set_Pos(x, y + 1);
        for (u8 i = 0; i < 8; i++) {  // 写入8列数据
            OLED_SSD1315_Write_Data(F8X16[char_offset * 16 + i + 8]);
        }
    } 
    // 8x8字体处理（占1页，6列）
    else {
        OLED_SSD1315_Set_Pos(x, y);
        for (u8 i = 0; i < 6; i++) {  // 6列数据（实际宽度6像素）
            OLED_SSD1315_Write_Data(F6x8[char_offset][i]);
        }
    }
}

/**
 * @brief 显示字符串（自动换行可选）
 * @param x,y 起始坐标（x:列, y:页）
 * @param str 字符串指针（以'\0'结尾的ASCII字符串）
 * @param size 字体大小 (8/16)
 * @param wrap 是否自动换行（true=超出屏幕宽度时换行，false=超出则截断）
 * @note 字符步进：
 *       - 8x8字体：每字符占6列 → 步进+6
 *       - 16x16字体：每字符占8列 → 步进+8
 *       换行逻辑：
 *       - 换行时y增加：8x8字体+1页，16x16字体+2页
 *       - 若y超出最大页（7），则回滚到0页
 */
void OLED_SSD1315_ShowString(u8 x, u8 y, const char* str, u8 size, bool wrap) {
    while (*str) {  // 遍历字符串直到结束符'\0'
        if (x >= OLED_WIDTH) {  // 列坐标超出屏幕宽度
            if (wrap) {  // 允许换行
                x = 0;  // 列回滚到0
                y += (size == 16) ? 2 : 1;  // 页增加（16字体占2页）
                if (y >= 8) y = 0;  // 页溢出回滚
            } else {
                break;  // 不换行则截断字符串
            }
        }
        OLED_SSD1315_ShowChar(x, y, *str++, size);  // 显示当前字符并移动到下一个
        x += (size == 16) ? 8 : 6;  // 按字体宽度调整列步进
    }
}

/**
  * @brief  显示定长数字（自动补零，固定宽度）
  * @param  x: 起始列坐标 (0~127)
  * @param  y: 起始页坐标 (0~7)
  * @param  num: 要显示的数字（支持0~4294967295，32位无符号整数）
  * @param  len: 显示位数（不足时补零，超出时显示完整数字）
  *             - 示例：len=4, num=12 → 显示"0012"
  *             - 示例：len=3, num=1234 → 显示"1234"（超出时不截断）
  * @param  size: 字体大小 (8或16)
  * @note   实现逻辑：
  *         1. 使用snprintf将数字格式化为字符串（%0*d → 不足位补零）
  *         2. 调用ShowString显示格式化后的字符串
  *         优势：
  *         - 固定宽度显示，适合表格/数据对齐场景
  *         - 使用静态缓冲区（16字节），避免动态内存分配
  */
void OLED_SSD1315_ShowNum(u8 x, u8 y, uint32_t num, u8 len, u8 size) 
{
    char str[16];  // 缓冲区（足够容纳32位最大数"4294967295"+结束符）
    
    /* 格式化数字：%0*d → 按len指定宽度，不足位补零 */
    snprintf(str, sizeof(str), "%0*d", len, num);  // 安全格式化（避免缓冲区溢出）
    
    /* 调用字符串显示函数（关闭自动换行） */
    OLED_SSD1315_ShowString(x, y, str, size, false);
}

/**
 * @brief 快速计算整数幂（辅助函数，用于数字显示）
 * @param base 基数（如10）
 * @param exponent 指数（如3 → 10^3=1000）
 * @return 计算结果（base^exponent）
 * @note 用途：在自定义数字显示函数中拆分数字的每一位（如提取百位、十位）
 *       溢出保护：当结果超过uint32_t最大值时返回UINT32_MAX
 */
uint32_t OLED_Math_Pow(u8 base, u8 exponent)
{
    uint32_t result = 1;
    while (exponent--) {
        result *= base;
        // 溢出保护：若下一次乘法会溢出，则返回最大值
        if (result > UINT32_MAX / base) {
            return UINT32_MAX;
        }
    }
    return result;
}

/**
 * @brief 显示16x16中文字符（需字库支持）
 * @param x 列起始位置 (0~127)
 * @param y 行起始位置 (页地址，0~7)
 * @param index 汉字在字库中的索引（Hzk数组的索引）
 * @note 字库要求：
 *       - 汉字点阵存储在Hzk数组（16x16像素，每字32字节）
 *       - 索引与汉字对应关系需在字库文件中定义（如"中"对应index=0）
 *       显示逻辑：
 *       1. 汉字占16列×16行 → 需2页（y和y+1）
 *       2. 逐列写入上半部分（16字节）和下半部分（16字节）
 */
void OLED_SSD1315_ShowChinese(u8 x, u8 y, u8 index)
{
    // 参数边界检查（避免超出屏幕）
    x = (x >= OLED_WIDTH - 15) ? OLED_WIDTH - 16 : x;  // 确保16列显示空间
    y = (y >= OLED_PAGE_NUM - 1) ? OLED_PAGE_NUM - 2 : y;  // 确保2页显示空间

    // 显示汉字上半部分（8行，16列）
    OLED_SSD1315_Set_Pos(x, y);
    for (u8 t = 0; t < 16; t++) {  // 写入16列数据
        OLED_SSD1315_Write_Data(Hzk[2 * index][t]);
    }

    // 显示汉字下半部分（8行，16列）
    OLED_SSD1315_Set_Pos(x, y + 1);
    for (u8 t = 0; t < 16; t++) {  // 写入16列数据
        OLED_SSD1315_Write_Data(Hzk[2 * index + 1][t]);
    }
}

/**
 * @brief 显示位图（自定义图像）
 * @param x0 起始列 (0~127)
 * @param y0 起始行（像素行，0~63）
 * @param x1 结束列 (x0+1~128)
 * @param y1 结束行（像素行，y0+1~64）
 * @param bmp 位图数据数组（按页组织，每字节控制8行像素）
 * @return true: 显示成功, false: 参数无效
 * @note 位图格式要求：
 *       - 数据按页存储（y0~y1对应的页）
 *       - 每页数据为x0~x1的列数据
 *       - 示例：16x16图像 → 2页×16列=32字节
 */
bool OLED_SSD1315_DrawBitmap(u8 x0, u8 y0, u8 x1, u8 y1, const u8 *bmp)
{
    // 参数校验（确保坐标有效）
    if (x0 >= OLED_WIDTH || y0 >= OLED_HEIGHT || 
        x1 > OLED_WIDTH || y1 > OLED_HEIGHT ||
        x0 >= x1 || y0 >= y1) {
        return false;
    }

    uint16_t index = 0;  // 位图数据索引
    u8 page_start = y0 / 8;  // 起始页（像素行y0对应的页）
    u8 page_end = (y1 - 1) / 8;  // 结束页（像素行y1-1对应的页）

    // 按页写入数据
    for (u8 page = page_start; page <= page_end; page++) {
        OLED_SSD1315_Set_Pos(x0, page);  // 定位到当前页的起始列
        
        // 写入当前页的x0~x1列数据
        for (u8 col = x0; col < x1; col++) {
            if (!OLED_SSD1315_Write_Data(bmp[index++])) {  // 写入1字节并检查通信
                return false;
            }
        }
    }
    return true;
}

/**
  * @brief  OLED控制器初始化（核心配置函数）
  * @note   初始化流程：
  *         1. 初始化I2C总线（GPIO配置、时序初始化）
  *         2. 延迟200ms（等待OLED电源稳定）
  *         3. 发送初始化命令序列（配置显示模式、电源、地址映射等）
  *         4. 开启显示
  *         命令详解：
  *         - 0xAE：关闭显示（初始化阶段先关闭，避免乱码）
  *         - 0x00/0x10：设置列地址低位/高位（初始化为0）
  *         - 0x40：设置起始行地址为0（从顶部开始扫描）
  *         - 0xB0：设置初始页地址为0
  *         - 0x81+0xFF：对比度控制（0xFF为最大亮度）
  *         - 0xA1：段重映射（列地址反转，适配屏幕布局）
  *         - 0xA6：正常显示（非反色模式）
  *         - 0xA8+0x3F：多路复用比率（64行屏幕对应0x3F）
  *         - 0xC8：COM扫描方向（行地址反转，从下到上扫描）
  *         - 0xD3+0x00：显示偏移（无偏移）
  *         - 0xD5+0x80：时钟分频（默认值，振荡器频率）
  *         - 0xD8+0x05：关闭区域颜色模式（单色屏无需配置）
  *         - 0xD9+0xF1：预充电周期（15个时钟周期，适合3.3V电源）
  *         - 0xDA+0x12：COM引脚配置（硬件引脚映射，64行屏幕专用）
  *         - 0xDB+0x30：VCOMH电压（0.83×VCC，影响亮度和对比度）
  *         - 0x8D+0x14：启用电荷泵（内部升压）
  *         - 0xAF：开启显示（完成初始化）
  */
void OLED_SSD1315_Config(void)
{
	IIC_Init();  // 初始化软件I2C（配置GPIO为推挽输出，设置初始电平）

	Delay_ms(200);  // 等待OLED电源稳定（重要，避免初始化失败）

	// 发送初始化命令序列
	OLED_SSD1315_Dat_or_Cmd(0xAE, OLED_CMD);	// 关闭显示（Display OFF）
	OLED_SSD1315_Dat_or_Cmd(0x00, OLED_CMD);	// 设置列地址低位（0x00~0x0F）
	OLED_SSD1315_Dat_or_Cmd(0x10, OLED_CMD);	// 设置列地址高位（0x10~0x1F）
	OLED_SSD1315_Dat_or_Cmd(0x40, OLED_CMD);	// 设置起始行地址（0x40=第0行）
	OLED_SSD1315_Dat_or_Cmd(0xB0, OLED_CMD);	// 设置页地址（初始为页0）
	OLED_SSD1315_Dat_or_Cmd(0x81, OLED_CMD);	// 对比度控制命令
	OLED_SSD1315_Dat_or_Cmd(0xFF, OLED_CMD);	// 对比度值（0xFF=最大亮度）
	OLED_SSD1315_Dat_or_Cmd(0xA1, OLED_CMD);	// 段重映射（列地址反转，127→0）
	OLED_SSD1315_Dat_or_Cmd(0xA6, OLED_CMD);	// 正常显示（A6=正常，A7=反色）
	OLED_SSD1315_Dat_or_Cmd(0xA8, OLED_CMD);	// 设置多路复用比率命令
	OLED_SSD1315_Dat_or_Cmd(0x3F, OLED_CMD);	// 比率=63（0x3F=64行屏幕）
	OLED_SSD1315_Dat_or_Cmd(0xC8, OLED_CMD);	// COM扫描方向反转（从下到上）
	OLED_SSD1315_Dat_or_Cmd(0xD3, OLED_CMD);	// 设置显示偏移命令
	OLED_SSD1315_Dat_or_Cmd(0x00, OLED_CMD);	// 偏移量=0（无垂直偏移）

	OLED_SSD1315_Dat_or_Cmd(0xD5, OLED_CMD);	// 设置时钟分频命令
	OLED_SSD1315_Dat_or_Cmd(0x80, OLED_CMD);	// 分频比=1，振荡器频率=默认

	OLED_SSD1315_Dat_or_Cmd(0xD8, OLED_CMD);	// 设置区域颜色模式命令
	OLED_SSD1315_Dat_or_Cmd(0x05, OLED_CMD);	// 默认值（单色屏无需修改）

	OLED_SSD1315_Dat_or_Cmd(0xD9, OLED_CMD);	// 设置预充电周期命令
	OLED_SSD1315_Dat_or_Cmd(0xF1, OLED_CMD);	// 预充电=15clk，放电=1clk

	OLED_SSD1315_Dat_or_Cmd(0xDA, OLED_CMD);	// 设置COM引脚配置命令
	OLED_SSD1315_Dat_or_Cmd(0x12, OLED_CMD);	// 引脚配置=交替（适合64行屏幕）

	OLED_SSD1315_Dat_or_Cmd(0xDB, OLED_CMD);	// 设置VCOMH电压命令
	OLED_SSD1315_Dat_or_Cmd(0x30, OLED_CMD);	// VCOMH=0.83V（3.3V供电时）

	OLED_SSD1315_Dat_or_Cmd(0x8D, OLED_CMD);	// 电荷泵配置命令
	OLED_SSD1315_Dat_or_Cmd(0x14, OLED_CMD);	// 启用电荷泵（内部升压）

	OLED_SSD1315_Dat_or_Cmd(0xAF, OLED_CMD);	// 开启显示（Display ON）
}
